import { isNil } from 'lodash-es'
import { appConfig } from '../config/app';
import { BaseType, dayjs, IFormat } from '../index';


const formatImpl: Record<string, (val: any, params?: any) => string> = {
  BankAccount: (val: string) => formatBankAccount(val),
  Boolean: (val: any): string => val ? '是' : '否',
  CnCurrency: (val: number) => formatCnCurrency((val || 0) / appConfig.number.currencyUnitValue),
  CnNumberUnit: (val: number) => formatCnNumberUnit(val || 0),
  Currency: (val: BaseType, precision?: number) => {
    if (val === '-') {
      return '-'
    } else {
      return formatCurrency((val as number || 0) / appConfig.number.currencyUnitValue, precision || appConfig.number.currencyPrecision);
    }
  },
  Date: (val: any, pattern = 'YYYY-MM-DD') => dayjs(val).format(pattern),
  Datetime: (val: any) => dayjs(val).format('YYYY-MM-DD HH:mm:ss'),
  Decimal: (val: number, precision?: number) => formatCurrency((val || 0) / appConfig.number.decimalUnitValue, precision || appConfig.number.decimalPrecision),
  Integer: (val: number) => formatCurrency(val || 0, 0),
  Number: (val: number, precision?: number) => formatCurrency(val || 0, isNil(precision) ? appConfig.number.numberPrecision : precision),
  Percent: (val: number, precision?: number) => formatCurrency(val * 100, precision) + '%',
  String: (val: any) => val,
  Mobile: (val: any, arr = [3, 4]) => maskStr(val, arr[0], arr[1]),
  IdNo: (val: any, arr = [6, 4]) => maskStr(val, arr[0], arr[1]),
  Text: (val: any) => val,
}

export type FormatType = keyof IFormat

export const format = (val: any, type: FormatType, params?: any): string => {
  if (val == null || val === 'undefined' || val === 'null') return '';
  if (type == null) return val;
  if (params === '') params = undefined;
  return formatImpl[type]?.(val, params) ?? val;
}

export const fmt = format

export const addFormat = (type: string, fn: (val: any, params?: any) => string): void => {
  formatImpl[type] = fn;
}

const formatCurrency = (val: BaseType, decimal = 2): string => {
  if (val === '-') return '-'
  if (!val && val !== 0) return ''
  val = parseFloat((val + '').replace(/[^\d\\.-]/g, '')).toFixed(decimal) + ''
  let left: any[]
  let right = ''
  if (val.includes('.')) {
    left = val.split('.')[0].split('').reverse()
    right = '.' + val.split('.')[1]
  } else {
    left = val.split('').reverse()
  }

  let str = ''
  for (let i = 0; i < left.length; i++) {
    str += left[i] + ((i + 1) % 3 === 0 && i + 1 !== left.length ? ',' : '')
  }

  const out = str.split('').reverse().join('') + right
  if (out.includes('-,')) {
    return out.replace('-,', '-')
  } else {
    return out
  }
}

const formatBankAccount = (str: string): string => (str ? str.replace(/\s/g, '').replace(/(\d{4})(?=\d)/g, '$1 ') : '')

const NUM_TO_CN_UNITS = ['', '', '', '', '', '万', '十万', '百万', '千万', '亿', '十亿', '百亿', '千亿', '万亿']

const formatCnNumberUnit = (num: number): string => {
  if (num) {
    const len = String(num).length
    return len < NUM_TO_CN_UNITS.length ? NUM_TO_CN_UNITS[len] : ''
  } else {
    return ''
  }
}

const CN_CURRENCY_FRACTIONS = ['角', '分']
const CN_CURRENCY_DIGITS = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
const CN_CURRENCY_UNITS = [['元', '万', '亿'], ['', '拾', '佰', '仟']]
const CHINA_CURRENCY_REGS = [/零./, /(零.)*零$/, /^$/, /(零.)*零元/, /(零.)+/g, /^整$/]

const formatCnCurrency = (num: number): string => {
  if (isNil(num)) return ''
  const head = num < 0 ? '欠' : ''
  num = Math.abs(num)
  let str = ''
  for (let i = 0; i < CN_CURRENCY_FRACTIONS.length; i++) {
    str += (CN_CURRENCY_DIGITS[Math.floor(num * 10 * Math.pow(10, i)) % 10] + CN_CURRENCY_FRACTIONS[i]).replace(CHINA_CURRENCY_REGS[0], '')
  }
  str = str || '整'
  num = Math.floor(num)

  for (let i = 0; i < CN_CURRENCY_UNITS[0].length && num > 0; i++) {
    let p = ''
    for (let j = 0; j < CN_CURRENCY_UNITS[1].length && num > 0; j++) {
      p = CN_CURRENCY_DIGITS[num % 10] + CN_CURRENCY_UNITS[1][j] + p
      num = Math.floor(num / 10)
    }
    str = p.replace(CHINA_CURRENCY_REGS[1], '').replace(CHINA_CURRENCY_REGS[2], '零') + CN_CURRENCY_UNITS[0][i] + str
  }
  return head + str.replace(CHINA_CURRENCY_REGS[3], '元').replace(CHINA_CURRENCY_REGS[4], '零').replace(CHINA_CURRENCY_REGS[5], '零元整')
}

export function maskStr(str: any, start: number, end: number) {
  if (str === null || str === undefined || str === '') {
    return '';
  }
  if (typeof str === 'number') {
    str = str.toString();
  }
  if (typeof str !== 'string') {
    return str;
  }
  if (start < 0 || end < 0 || start >= str.length || start >= str.length - end) {
    return str; // 返回原字符串
  }
  const actualEnd = str.length - end;
  const maskedPart = '*'.repeat(actualEnd - start); // 用 * 替代中间部分
  return str.slice(0, start) + maskedPart + str.slice(actualEnd);
}
